package cn.edu.dlmu.cogo.framework.context;

import cn.edu.dlmu.cogo.framework.annotation.Autowired;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ReflectUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * @author yixi
 * Bean对象装配器，用以实现 @AutoWired注解
 */
public class Refresher {

    private final ApplicationContext CONTAINER;

    private final Object INSTANCE;

    private final List<Field> Fields;

    private final List<Method> Methods;

    public Refresher(Class<?> clazz){
        CONTAINER = ContextContainer.getApplicationContext();
        INSTANCE = CONTAINER.getBean(clazz);
        Fields = Arrays.asList(ReflectUtil.getFields(clazz, field -> AnnotationUtil.getAnnotation(field, Autowired.class) != null));
        Methods = Arrays.asList(ReflectUtil.getMethods(clazz,method -> AnnotationUtil.getAnnotation(method, Autowired.class) != null));
    }

    public void refresh(){
        refreshFields();
        refreshMethods();
    }

    private void refreshFields(){
        Fields.forEach(field -> {
            String beanName = field.getAnnotation(Autowired.class).value();
            Class<?> fieldType = field.getType();
            Object bean = !"".equals(beanName) ? CONTAINER.getBean(beanName) : CONTAINER.getBean(fieldType);
            //通过接口实现类自动装配到接口中
            if (bean == null){
                for (Class<?> aClass : CONTAINER.getClasses()) {
                    for (Class<?> anInterface : aClass.getInterfaces()) {
                        if (anInterface == fieldType){
                            ReflectUtil.setFieldValue(INSTANCE,field,CONTAINER.getBean(aClass));
                            return;
                        }
                    }
                }
            }
            //强制性非空检查
            if (bean == null){
                throw new NullPointerException("[CogoFramework]找不到Bean对象实例[" + field.getType().getName() + "]");
            }
            ReflectUtil.setFieldValue(INSTANCE,field,bean);
        });
    }

    private void refreshMethods(){
        Methods.forEach(method -> {
            Object[] params = new Object[method.getParameterTypes().length];
            for (int i = 0; i < method.getParameterTypes().length; i++) {
                params[i] = CONTAINER.getBean(method.getParameterTypes()[i]);
                if (params[i] == null) {
                    throw new NullPointerException("[CogoFramework]找不到Bean对象实例[" + method.getParameterTypes()[i].getName() + "]");
                }
            }
            ReflectUtil.invoke(INSTANCE, method, params);
        });
    }
}
